//from: http://west-wind.com/weblog/posts/1109.aspx

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

using System.Globalization ;

namespace stsdev
{

	/// <summary>
	/// Input form class that displays a dialog for capturing a single value that can be of several common types.
	/// </summary>
	[Description("An input form that allows to easily edit a single value in a dialog.")]
	public class InputForm : System.Windows.Forms.Form
	{
		private System.Windows.Forms.Button btnOK;
		private System.Windows.Forms.Button btnCancel;
		private System.Windows.Forms.Label lblLabelText;
		private wwTextBox txtInput;

		/// <summary>
		/// Used internally to track input value's type so the result can be returned in the same type.
		/// </summary>
		private Type InputType = typeof(string);
		private bool TextAlignmentSet = false;

		/// <summary>
		/// The initial value of that is to be edited in the textbox.
		/// </summary>
		[Description("The initial value of that is to be edited in the textbox.")]
		public object InitialValue 
		{
			set 
			{ 
				this.txtInput.Text = TypedValueToString(value);

				// *** Save the type so we can look convert back to it on the way back!
				this.InputType = value.GetType();
				this.oInitialValue = value;
			}
		}
		object oInitialValue = "";

		/// <summary>
		/// The result value from the textbox when exiting the input form. This value is of type object and the type depends on the InputType setting.
		/// </summary>
		[Description("The result value from the textbox when exiting the input form. This value is of type object and the type depends on the InputType setting.")]
		public object Result 
		{
			get 
			{ 
					return oResult;
			}
		}
		object oResult = null;

		/// <summary>
		/// The text used as the input prompt above the textbox that edits the input value.
		/// </summary>
		[Description("The text used as the input prompt above the textbox that edits the input value.")]
		public string LabelText 
		{
			get { return this.lblLabelText.Text; }
			set { this.lblLabelText.Text = value; }
		}

		public int LabelWidth  
		{
			set { this.txtInput.Width = value; }
		}
	
		/// <summary>
		/// A format string used with string.Format() to format the display the of the textbox value on startup
		/// </summary>
		[Description("A format string used with string.Format() to format the display the of the textbox value on startup")]
		public string DisplayFormat 
		{
			get { return this.cDisplayFormat; }
			set 
			{
				this.cDisplayFormat = value;
				this.txtInput.Text = string.Format(value,this.oInitialValue ); 
			}
		}
		string cDisplayFormat = "";
		
		/// <summary>
		/// Horizontal Alignment of the text displayed in the text box. Depending on the type of data displayed this may be set automatically. Set this value after you set the input type.
		/// </summary>
		[Description("Horizontal Alignment of hte text displayed in the text box. Depending on the type of data displayed this may be set automatically. Set this value after you set the input type.")]
		public HorizontalAlignment TextAlign
		{
			set 
			{ 
			  this.txtInput.TextAlign = value; 
			  this.TextAlignmentSet = true;
			}
		}

		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public InputForm()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.btnOK = new System.Windows.Forms.Button();
            this.btnCancel = new System.Windows.Forms.Button();
            this.lblLabelText = new System.Windows.Forms.Label();
            this.txtInput = new stsdev.wwTextBox();
            this.SuspendLayout();
            // 
            // btnOK
            // 
            this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.btnOK.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnOK.Location = new System.Drawing.Point(177, 64);
            this.btnOK.Name = "btnOK";
            this.btnOK.Size = new System.Drawing.Size(75, 23);
            this.btnOK.TabIndex = 2;
            this.btnOK.Text = "OK";
            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
            // 
            // btnCancel
            // 
            this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnCancel.Location = new System.Drawing.Point(255, 63);
            this.btnCancel.Name = "btnCancel";
            this.btnCancel.Size = new System.Drawing.Size(75, 23);
            this.btnCancel.TabIndex = 3;
            this.btnCancel.Text = "Cancel";
            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
            // 
            // lblLabelText
            // 
            this.lblLabelText.AutoSize = true;
            this.lblLabelText.Location = new System.Drawing.Point(16, 8);
            this.lblLabelText.Name = "lblLabelText";
            this.lblLabelText.Size = new System.Drawing.Size(71, 13);
            this.lblLabelText.TabIndex = 3;
            this.lblLabelText.Text = "Please enter:";
            // 
            // txtInput
            // 
            this.txtInput.InputType = stsdev.TextBoxInputTypes.Text;
            this.txtInput.Location = new System.Drawing.Point(16, 28);
            this.txtInput.Name = "txtInput";
            this.txtInput.Size = new System.Drawing.Size(312, 21);
            this.txtInput.TabIndex = 1;
            // 
            // InputForm
            // 
            this.AcceptButton = this.btnOK;
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 14);
            this.CancelButton = this.btnCancel;
            this.ClientSize = new System.Drawing.Size(338, 95);
            this.Controls.Add(this.txtInput);
            this.Controls.Add(this.lblLabelText);
            this.Controls.Add(this.btnCancel);
            this.Controls.Add(this.btnOK);
            this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "InputForm";
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "InputForm";
            this.TopMost = true;
            this.Activated += new System.EventHandler(this.InputForm_Activated);
            this.ResumeLayout(false);
            this.PerformLayout();

		}
		#endregion

		private void btnCancel_Click(object sender, System.EventArgs e)
		{
			this.DialogResult = DialogResult.Cancel;
		}

		private void btnOK_Click(object sender, System.EventArgs e)
		{
			
			try 
			{
				this.oResult = StringToTypedValue( txtInput.Text.Trim(), this.InputType);
			}
			catch
			{
				MessageBox.Show("Invalid value entered","Input Error",
					            MessageBoxButtons.OK,MessageBoxIcon.Exclamation);
				return;  // returns back to form
			}
					
			this.DialogResult = DialogResult.OK;
		}

		/// <summary>
		/// Override text alignment based on the input type - specifically numeric values show right aligned,
		/// but only if TextAlignment wasn't previously set
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void InputForm_Activated(object sender, System.EventArgs e)
		{
			if (!this.TextAlignmentSet) 
			{
				if (this.InputType ==typeof( int) ||
					this.InputType == typeof( decimal) ||
					this.InputType == typeof( float) ) 
				{
					this.TextAlign = HorizontalAlignment.Right;
					this.txtInput.InputType = TextBoxInputTypes.Numeric;
				}
				else if (this.InputType == typeof( DateTime ) )
					this.txtInput.InputType = TextBoxInputTypes.Date;

				
				this.TextAlignmentSet = true;
			}
		}		

		/// <summary>
		/// Converts a type to string if possible. This method supports an optional culture generically on any value.
		/// It calls the ToString() method on common types and uses a type converter on all other objects
		/// if available
		/// </summary>
		/// <param name="RawValue">The Value or Object to convert to a string</param>
		/// <param name="Culture">Culture for numeric and DateTime values</param>
		/// <returns>string</returns>
		public static string TypedValueToString(object RawValue,CultureInfo Culture) 
		{
			Type ValueType = RawValue.GetType();
			string Return = null;

			if (ValueType == typeof(string) ) 
				Return = RawValue.ToString();
			else if ( ValueType == typeof(int) || ValueType == typeof(decimal) || 
				ValueType == typeof(double) || ValueType == typeof(float))
				Return = string.Format(Culture.NumberFormat,"{0}",RawValue);
			else if(ValueType == typeof(DateTime))
				Return =  string.Format(Culture.DateTimeFormat,"{0}",RawValue);
			else if(ValueType == typeof(bool))
				Return = RawValue.ToString();
			else if(ValueType == typeof(byte))
				Return = RawValue.ToString();
			else if(ValueType.IsEnum)
				Return = RawValue.ToString();
			else 
			{
				// Any type that supports a type converter
				System.ComponentModel.TypeConverter converter = 
					System.ComponentModel.TypeDescriptor.GetConverter( ValueType );
				if (converter != null && converter.CanConvertTo(typeof(string)) )
					Return = converter.ConvertToString(null,Culture,RawValue );
				else
					// Last resort - just call ToString() on unknown type
					Return = RawValue.ToString();

			}
		
			return Return;
		}

		/// <summary>
		/// Converts a type to string if possible. This method uses the current culture for numeric and DateTime values.
		/// It calls the ToString() method on common types and uses a type converter on all other objects
		/// if available.
		/// </summary>
		/// <param name="RawValue">The Value or Object to convert to a string</param>
		/// <param name="Culture">Culture for numeric and DateTime values</param>
		/// <returns>string</returns>
		public static string TypedValueToString(object RawValue) 
		{
			return TypedValueToString(RawValue,CultureInfo.CurrentCulture);
		}

		/// <summary>
		/// Turns a string into a typed value. Useful for auto-conversion routines
		/// like form variable or XML parsers.
		/// <seealso>Class wwUtils</seealso>
		/// </summary>
		/// <param name="SourceString">
		/// The string to convert from
		/// </param>
		/// <param name="TargetType">
		/// The type to convert to
		/// </param>
		/// <param name="Culture">
		/// Culture used for numeric and datetime values.
		/// </param>
		/// <returns>object. Throws exception if it cannot be converted.</returns>
		public static object StringToTypedValue(string SourceString, Type TargetType, CultureInfo Culture ) 
		{
			object Result = null;

			if ( TargetType == typeof(string) )
				Result = SourceString;
			else if (TargetType == typeof(int))  
				Result = int.Parse( SourceString, System.Globalization.NumberStyles.Integer, Culture.NumberFormat );			
			else if (TargetType  == typeof(byte) )  
				Result = Convert.ToByte(SourceString);				
			else if (TargetType  == typeof(decimal))  
				Result = Decimal.Parse(SourceString,System.Globalization.NumberStyles.Any, Culture.NumberFormat);
			else if (TargetType  == typeof(double))    
				Result = Double.Parse( SourceString,System.Globalization.NumberStyles.Any, Culture.NumberFormat);				
			else if (TargetType == typeof(bool)) 
			{
				if (SourceString.ToLower() == "true" || SourceString.ToLower() == "on" || SourceString == "1")
					Result = true;
				else
					Result = false;
			}
			else if (TargetType == typeof(DateTime))  
				Result = Convert.ToDateTime(SourceString,Culture.DateTimeFormat);	
			else if (TargetType.IsEnum)
				Result = Enum.Parse(TargetType,SourceString);
			else   
			{
				System.ComponentModel.TypeConverter converter = System.ComponentModel.TypeDescriptor.GetConverter(TargetType);
				if (converter != null && converter.CanConvertFrom(typeof(string)) )
					Result = converter.ConvertFromString( null, Culture, SourceString );
				else  
				{
					System.Diagnostics.Debug.Assert(false,"Type Conversion not handled in StringToTypedValue\r\n" + 
						TargetType.Name + " " + SourceString );
					throw(new Exception("Type Conversion not handled in StringToTypedValue"));
				}
			}

			return Result;
		}

		/// <summary>
		/// Turns a string into a typed value. Useful for auto-conversion routines
		/// like form variable or XML parsers.
		/// </summary>
		/// <param name="SourceString">The input string to convert</param>
		/// <param name="TargetType">The Type to convert it to</param>
		/// <returns>object reference. Throws Exception if type can not be converted</returns>
		public static object StringToTypedValue(string SourceString, Type TargetType ) 
		{
			return StringToTypedValue(SourceString,TargetType,CultureInfo.CurrentCulture);
		}

		/// <summary>
		/// Visual Basic Style Parameters
		/// </summary>
		/// <param name="Prompt"></param>
		/// <param name="Title"></param>
		/// <param name="DefaultResponse"></param>
		/// <returns></returns>
		public static object InputBox(string Prompt, string Title, object InitialValue, string Format)
		{
			if (InitialValue == null)
				InitialValue = "";

			InputForm Input = new InputForm();
			Input.Text = Title; 
           
			Input.LabelText = Prompt;
			Input.InitialValue = InitialValue;

			if (Format != null)
				Input.DisplayFormat = Format;

			if (Input.ShowDialog() == DialogResult.Cancel)
				return null;
		
			return Input.Result;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="Prompt"></param>
		/// <param name="Title"></param>
		/// <param name="InitialValue"></param>
		/// <returns></returns>
		public static object InputBox(string Prompt, string Title, object InitialValue) 
		{
			return InputBox(Prompt,Title,InitialValue,null);
		}



	}

	
}
